﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Runtime.CompilerServices;

using ConstructionBidOnline.DAL;
using ConstructionBidOnline.DAL.dsRegisteredUserTableAdapters;
using ConstructionBidOnline.Common;

namespace ConstructionBidOnline.Biz
{
    /// <summary>
    /// RegisteredUser Business Object
    /// </summary>

    public class RegisteredUser : BOBase
    {
        #region Types

        #region RBS Error Enums

        public enum RbsError : int
        {
            /// <summary>
            /// No error detected.
            /// </summary>
            NO_ERROR = 0,

            /// <summary>
            /// Username may not be NULL nor zero-length.
            /// </summary>
            INVALID_USERNAME,

            /// <summary>
            /// The UserID supplied does not exist in the RBS database.
            /// </summary>
            INVALID_USERID,

            /// <summary>
            /// The supplied username/password do not match any RBS users.
            /// </summary>
            INVALID_CREDENTIALS,

            /// <summary>
            /// The username is valid; the password is expired; logon failed.
            /// </summary>
            PASSWORD_CHANGE_REQUIRED,

            /// <summary>
            /// The user is shown as already logged-on and Prohibit Concurrent Logins is in effect for this user.
            /// </summary>
            ALREADY_LOGGED_ON,

            /// <summary>
            /// The specified user account is locked out.
            /// </summary>
            ACCOUNT_LOCKED_OUT,

            /// <summary>
            /// The specified user account has expired.
            /// </summary>
            ACCOUNT_EXPIRED,

            /// <summary>
            /// The specified user account is not active.
            /// </summary>
            ACCOUNT_INACTIVE,

            /// <summary>
            /// The specified username already exists in the RBS
            /// </summary>
            ALREADY_EXISTS,

            /// <summary>
            /// No database records were found
            /// </summary>
            NO_RECORDS_FOUND,

            /// <summary>
            /// A database constraint violation was detected.
            /// </summary>
            CONSTRAINT_VIOLATION,

            /// <summary>
            /// The called function requires the caller to be authenticated.
            /// </summary>
            CALLER_NOT_AUTHENTICATED,

            /// <summary>
            /// An unknown exception has occurred.
            /// </summary>
            OTHER_EXCEPTION,

            /// <summary>
            /// One or more function parameters were invalid as a result of being null.
            /// </summary>
            INVALID_NULL_PARAMETER,

            /// <summary>
            /// The specified password is either null or does not meet the application's length requirements.
            /// </summary>
            PASSWORD_TOO_SHORT,

            /// <summary>
            /// The specified company is non-production/pending and the user is NOT a Site Admin.
            /// </summary>
            ACCOUNT_PENDING,

            /// <summary>
            /// The specified user has no associated roles.
            /// </summary>
            USER_NO_ROLES,

            /// <summary>
            /// The specified user's email id is not verified .
            /// </summary>
            USER_EMAIL_NOT_VERIFIED
        }

        #endregion

        #endregion

        #region Constants

        // Name of the session variable that holds the SubAdmin object for the currently logged-on user.
        public static readonly string PROP_CURRENT = "__RegisteredUser::Current";

        // Role-based Security Constants
        private static readonly string REGISTEREDUSER_DFLT_PSWDSALT = "_5hW)+32Kdu*@#%Djd?3~j45";
        private static readonly int REGISTEREDUSER_DFLT_MINPSWDLEN = 6;


        #endregion

        #region Construction / Disposal

        /// <summary>
        /// Default constructor.
        /// </summary>
        protected RegisteredUser() { }

        #endregion

        #region Public Properties

        #region Static Properties

        /// <summary>
        /// The Registered User object representing the currently authenticated user.
        /// </summary>
        public static RegisteredUser Current
        {
            get
            {
                if (SessionMgr.Session[PROP_CURRENT] == null)
                {
                    lock (typeof(RegisteredUser))
                    {
                        if (SessionMgr.Session[PROP_CURRENT] == null)
                            SessionMgr.Session[PROP_CURRENT] = new RegisteredUser();
                    }
                }
                return ((RegisteredUser)SessionMgr.Session[PROP_CURRENT]);
            }
        }

        #endregion

        #region Instance Properties

        /// <summary>
        /// PKID of the RegisteredUser.
        /// </summary>
        public int RegisteredUserID
        {
            get { return _RegisteredUserID; }
            set
            {
                if (_RegisteredUserID != value)
                {
                    if (OnPropertyChanging("RegisteredUserID", _RegisteredUserID, value))
                    {
                        int oldValue = _RegisteredUserID;
                        _RegisteredUserID = value;

                        OnPropertyChanged("RegisteredUserID", oldValue, value);
                    }
                }
            }
        }  private int _RegisteredUserID = -1;

        /// <summary>
        /// Alternate key: GUID associated with this RegisteredUserD. Use this alternate key in URL query strings
        /// and/or when importing/exporting data; never expose the RegisteredUserID outside of the application.
        /// </summary>
        public Guid RegisteredUserGUID
        {
            get { return (_registereduserGUID); }
            set { _registereduserGUID = value; }
        } private Guid _registereduserGUID = Guid.Empty;




        /// <summary>
        /// Registered User Type.
        /// </summary>
        public string RegisteredUserType
        {
            get { return _registeredusertype; }
            set
            {
                if (_registeredusertype != value)
                {
                    if (OnPropertyChanging("RegisteredUserType", _registeredusertype, value))
                    {
                        string oldValue = _registeredusertype;
                        _registeredusertype = value;
                        OnPropertyChanged("RegisteredUserType", oldValue, value);
                    }
                }
            }
        }  private string _registeredusertype = null;


        /// <summary>
        /// UserName.
        /// </summary>
        public string UserName
        {
            get { return _username; }
            set
            {
                if (_username != value)
                {
                    if (OnPropertyChanging("UserName", _username, value))
                    {
                        string oldValue = _username;
                        _username = value;
                        OnPropertyChanged("UserName", oldValue, value);
                    }
                }
            }
        }  private string _username = null;



        /// <summary>
        /// EmailAddress.
        /// </summary>
        public string EmailAddress
        {
            get { return _emailaddress; }
            set
            {
                if (_emailaddress != value)
                {
                    if (OnPropertyChanging("EmailAddress", _emailaddress, value))
                    {
                        string oldValue = _emailaddress;
                        _emailaddress = value;
                        OnPropertyChanged("EmailAddress", oldValue, value);
                    }
                }
            }
        }  private string _emailaddress = null;


        /// <summary>
        /// Password.
        /// </summary>
        public string Password
        {
            get { return _password; }
            set
            {
                if (_password != value)
                {
                    if (OnPropertyChanging("Password", _password, value))
                    {
                        string oldValue = _password;
                        _password = value;
                        OnPropertyChanged("Password", oldValue, value);
                    }
                }
            }
        }  private string _password = null;


        /// <summary>
        /// True iff the RegisteredUser must change their password at first login.
        /// </summary>
        public bool IsPasswordChangeRequired
        {
            get { return _isPasswordChangeRequired; }
            set
            {
                if (_isPasswordChangeRequired != value)
                {
                    if (OnPropertyChanging("IsPasswordChangeRequired", _isPasswordChangeRequired, value))
                    {
                        bool oldValue = _isPasswordChangeRequired;
                        _isPasswordChangeRequired = value;
                        OnPropertyChanged("IsPasswordChangeRequired", oldValue, value);
                    }
                }
            }
        }  private bool _isPasswordChangeRequired = false;


        /// <summary>
        /// WorkPhone.
        /// </summary>
        public string WorkPhone
        {
            get { return _workphone; }
            set
            {
                if (_workphone != value)
                {
                    if (OnPropertyChanging("WorkPhone", _workphone, value))
                    {
                        string oldValue = _workphone;
                        _workphone = value;
                        OnPropertyChanged("WorkPhone", oldValue, value);
                    }
                }
            }
        }  private string _workphone = null;


        /// <summary>
        /// MobilePhone.
        /// </summary>
        public string MobilePhone
        {
            get { return _mobilephone; }
            set
            {
                if (_mobilephone != value)
                {
                    if (OnPropertyChanging("MobilePhone", _mobilephone, value))
                    {
                        string oldValue = _mobilephone;
                        _mobilephone = value;
                        OnPropertyChanged("MobilePhone", oldValue, value);
                    }
                }
            }
        }  private string _mobilephone = null;


        /// <summary>
        /// FirstName.
        /// </summary>
        public string FirstName
        {
            get { return _firstname; }
            set
            {
                if (_firstname != value)
                {
                    if (OnPropertyChanging("FirstName", _firstname, value))
                    {
                        string oldValue = _firstname;
                        _firstname = value;
                        OnPropertyChanged("FirstName", oldValue, value);
                    }
                }
            }
        }  private string _firstname = null;


        /// <summary>
        /// LastName.
        /// </summary>
        public string LastName
        {
            get { return _lastname; }
            set
            {
                if (_lastname != value)
                {
                    if (OnPropertyChanging("LastName", _lastname, value))
                    {
                        string oldValue = _lastname;
                        _lastname = value;
                        OnPropertyChanged("LastName", oldValue, value);
                    }
                }
            }
        }  private string _lastname = null;





        /// <summary>
        /// AddressLine1.
        /// </summary>
        public string AddressLine1
        {
            get { return _addressline1; }
            set
            {
                if (_addressline1 != value)
                {
                    if (OnPropertyChanging("AddressLine1", _addressline1, value))
                    {
                        string oldValue = _addressline1;
                        _addressline1 = value;
                        OnPropertyChanged("AddressLine1", oldValue, value);
                    }
                }
            }
        }  private string _addressline1 = null;



        /// <summary>
        /// AddressLine2.
        /// </summary>
        public string AddressLine2
        {
            get { return _addressline2; }
            set
            {
                if (_addressline2 != value)
                {
                    if (OnPropertyChanging("AddressLine2", _addressline2, value))
                    {
                        string oldValue = _addressline2;
                        _addressline2 = value;
                        OnPropertyChanged("AddressLine2", oldValue, value);
                    }
                }
            }
        }  private string _addressline2 = null;


        /// <summary>
        /// City.
        /// </summary>
        public string City
        {
            get { return _city; }
            set
            {
                if (_city != value)
                {
                    if (OnPropertyChanging("City", _city, value))
                    {
                        string oldValue = _city;
                        _city = value;
                        OnPropertyChanged("City", oldValue, value);
                    }
                }
            }
        }  private string _city = null;


        /// <summary>
        /// State.
        /// </summary>
        public string State
        {
            get { return _state; }
            set
            {
                if (_state != value)
                {
                    if (OnPropertyChanging("State", _state, value))
                    {
                        string oldValue = _state;
                        _state = value;
                        OnPropertyChanged("State", oldValue, value);
                    }
                }
            }
        }  private string _state = null;


        /// <summary>
        /// Country.
        /// </summary>
        public string Country
        {
            get { return _country; }
            set
            {
                if (_country != value)
                {
                    if (OnPropertyChanging("Country", _country, value))
                    {
                        string oldValue = _country;
                        _country = value;
                        OnPropertyChanged("Country", oldValue, value);
                    }
                }
            }
        }  private string _country = null;


        /// <summary>
        /// ZipCode.
        /// </summary>
        public string ZipCode
        {
            get { return _zipcode; }
            set
            {
                if (_zipcode != value)
                {
                    if (OnPropertyChanging("ZipCode", _zipcode, value))
                    {
                        string oldValue = _zipcode;
                        _zipcode = value;
                        OnPropertyChanged("ZipCode", oldValue, value);
                    }
                }
            }
        }  private string _zipcode = null;



        /// <summary>
        /// SecurityQuestion.
        /// </summary>
        public string SecurityQuestion
        {
            get { return _securityquestion; }
            set
            {
                if (_securityquestion != value)
                {
                    if (OnPropertyChanging("SecurityQuestion", _securityquestion, value))
                    {
                        string oldValue = _securityquestion;
                        _securityquestion = value;
                        OnPropertyChanged("SecurityQuestion", oldValue, value);
                    }
                }
            }
        }  private string _securityquestion = null;



        /// <summary>
        /// SecurityAnswer.
        /// </summary>
        public string SecurityAnswer
        {
            get { return _securityanswer; }
            set
            {
                if (_securityanswer != value)
                {
                    if (OnPropertyChanging("SecurityAnswer", _securityanswer, value))
                    {
                        string oldValue = _securityanswer;
                        _securityanswer = value;
                        OnPropertyChanged("SecurityAnswer", oldValue, value);
                    }
                }
            }
        }  private string _securityanswer = null;


        /// <summary>
        /// LoginCount of the RegisteredUser.
        /// </summary>
        public decimal LoginCount
        {
            get { return _logincount; }
            set
            {
                if (_logincount != value)
                {
                    if (OnPropertyChanging("LoginCount", _logincount, value))
                    {
                        decimal oldValue = _logincount;
                        _logincount = value;

                        OnPropertyChanged("LoginCount", oldValue, value);
                    }
                }
            }
        }  private decimal _logincount = -1;


        /// <summary>
        /// Date/time at which the RegisteredUser was last loged in to the application.
        /// </summary>
        public DateTime? LastLoginDate
        {
            get { return _lastlogindate; }
            set
            {
                if (_lastlogindate != value)
                {
                    if (OnPropertyChanging("LastLoginDate", _lastlogindate, value))
                    {
                        DateTime? oldValue = _lastlogindate;
                        _lastlogindate = value;
                        OnPropertyChanged("LastLoginDate", oldValue, value);
                    }
                }
            }
        }  private DateTime? _lastlogindate = null;


        /// <summary>
        /// Date/time at which the RegisteredUser has last modified his profile.
        /// </summary>
        public DateTime? LastModifiedDate
        {
            get { return _lastmodifieddate; }
            set
            {
                if (_lastmodifieddate != value)
                {
                    if (OnPropertyChanging("LastModifiedDate", _lastmodifieddate, value))
                    {
                        DateTime? oldValue = _lastmodifieddate;
                        _lastmodifieddate = value;
                        OnPropertyChanged("LastModifiedDate", oldValue, value);
                    }
                }
            }
        }  private DateTime? _lastmodifieddate = null;


        /// <summary>
        /// Date/time at which the RegisteredUser was created.
        /// </summary>
        public DateTime? IDCreatedOn
        {
            get { return _idcreatedon; }
            set
            {
                if (_idcreatedon != value)
                {
                    if (OnPropertyChanging("IDCreatedOn", _idcreatedon, value))
                    {
                        DateTime? oldValue = _idcreatedon;
                        _idcreatedon = value;
                        OnPropertyChanged("IDCreatedOn", oldValue, value);
                    }
                }
            }
        }  private DateTime? _idcreatedon = null;


        /// <summary>
        /// Date/time at which the Consultant Requested for registration.
        /// </summary>
        public DateTime? RequestDate
        {
            get { return _requestdate; }
            set
            {
                if (_requestdate != value)
                {
                    if (OnPropertyChanging("RequestDate", _requestdate, value))
                    {
                        DateTime? oldValue = _requestdate;
                        _requestdate = value;
                        OnPropertyChanged("RequestDate", oldValue, value);
                    }
                }
            }
        }  private DateTime? _requestdate = null;

        /// <summary>
        /// Date/time at which the Consultant Got confirmed Registration through Site Admin.
        /// </summary>
        public DateTime? ConfirmationDate
        {
            get { return _confirmationdate; }
            set
            {
                if (_confirmationdate != value)
                {
                    if (OnPropertyChanging("ConfirmationDate", _confirmationdate, value))
                    {
                        DateTime? oldValue = _confirmationdate;
                        _confirmationdate = value;
                        OnPropertyChanged("ConfirmationDate", oldValue, value);
                    }
                }
            }
        }  private DateTime? _confirmationdate = null;

        /// <summary>
        /// True iff the User got registered and email got verified (i.e. to be used in the application).
        /// </summary>
        public bool IsRegistered
        {
            get { return _isRegistered; }
            set
            {
                if (_isRegistered != value)
                {
                    if (OnPropertyChanging("IsRegistered", _isRegistered, value))
                    {
                        bool oldValue = _isRegistered;
                        _isRegistered = value;
                        OnPropertyChanged("IsRegistered", oldValue, value);
                    }
                }
            }
        }  private bool _isRegistered = false;


        /// <summary>
        /// True iff the Admin has made this RegisteredUser Active (i.e. to be used in the application).
        /// </summary>
        public bool IsActive
        {
            get { return _isActive; }
            set
            {
                if (_isActive != value)
                {
                    if (OnPropertyChanging("IsActive", _isActive, value))
                    {
                        bool oldValue = _isActive;
                        _isActive = value;
                        OnPropertyChanged("IsActive", oldValue, value);
                    }
                }
            }
        }  private bool _isActive = false;

        #endregion

        #endregion

        #region Public Methods

        #region CreateNew

        /// <summary>
        /// Creates a new, empty RegisteredUser object.
        /// </summary>
        public static RegisteredUser CreateNew()
        {
            RegisteredUser obj = new RegisteredUser();

            // Switch state to Added prior to initializing property values.
            obj.ObjState = ObjectState.Added;
            obj.RegisteredUserGUID = Guid.NewGuid();
            obj.IDCreatedOn = DateTime.Now;
            obj.IsRegistered = false;
            obj.IsActive = false;
            return (obj);
        }


        [MethodImpl(MethodImplOptions.Synchronized)]
        public static RegisteredUser CreateNew(RegisteredUserCollection collection)
        {
            RegisteredUser obj = CreateNew();

            // Get next/unique ID for the new object.
            int minVal = 0;
            foreach (RegisteredUser registereduser in collection)
            {
                if (registereduser.RegisteredUserID < minVal)
                    minVal = registereduser.RegisteredUserID;
            }
            obj.RegisteredUserID = --minVal;
            collection.Add(obj);

            return (obj);
        }

        #endregion

        #region GetAllRegisteredUsers

        /// <summary>
        /// Returns a collection of all RegisteredUsers.
        /// </summary>
        public static RegisteredUserCollection GetAllRegisteredUsers()
        {
            RegisteredUserTableAdapter adapter = new RegisteredUserTableAdapter();
            adapter.Connection = AppSettings.GetDbConn();

            dsRegisteredUser.RegisteredUserDataTable tbl = adapter.GetData(null);

            RegisteredUserCollection list = new RegisteredUserCollection();

            if (tbl.Rows.Count > 0)
            {
                foreach (dsRegisteredUser.RegisteredUserRow row in tbl.Rows)
                {
                    RegisteredUser registereduser = new RegisteredUser();
                    RelationalToObject(registereduser, row);
                    list.Add(registereduser);
                }
            }

            return (list);
        }

        #endregion

        #region GetRegisteredUsersByType

        /// <summary>
        /// Returns a collection of all RegisteredUsers.
        /// </summary>
        public static RegisteredUserCollection GetAllRegisteredUsersByType(string usertype)
        {
            RegisteredUserTableAdapter adapter = new RegisteredUserTableAdapter();
            adapter.Connection = AppSettings.GetDbConn();

            dsRegisteredUser.RegisteredUserDataTable tbl = adapter.GetDataByRegisteredUserType(usertype);

            RegisteredUserCollection list = new RegisteredUserCollection();

            if (tbl.Rows.Count > 0)
            {
                foreach (dsRegisteredUser.RegisteredUserRow row in tbl.Rows)
                {
                    RegisteredUser registereduser = new RegisteredUser();
                    RelationalToObject(registereduser, row);
                    list.Add(registereduser);
                }
            }

            return (list);
        }

        #endregion

        #region GetRegisteredUsersRegistrationStatus

        /// <summary>
        /// Returns a collection of all RegisteredUsers.
        /// </summary>
        public static RegisteredUserCollection GetAllRegisteredUsersRegistrationStatus(bool isRegistered)
        {
            RegisteredUserTableAdapter adapter = new RegisteredUserTableAdapter();
            adapter.Connection = AppSettings.GetDbConn();

            dsRegisteredUser.RegisteredUserDataTable tbl = adapter.GetDataByRegistrationStatus(isRegistered);

            RegisteredUserCollection list = new RegisteredUserCollection();

            if (tbl.Rows.Count > 0)
            {
                foreach (dsRegisteredUser.RegisteredUserRow row in tbl.Rows)
                {
                    RegisteredUser registereduser = new RegisteredUser();
                    RelationalToObject(registereduser, row);
                    list.Add(registereduser);
                }
            }

            return (list);
        }

        #endregion

        #region GetRegisteredUserByID

        /// <summary>
        /// Returns an RegisteredUser object for the specified 'RegisteredUserID' or null if no RegisteredUser with the specified parameter(s) exists.
        /// </summary>
        public static RegisteredUser GetRegisteredUserByID(int registereduserid)
        {
            RegisteredUserTableAdapter adapter = new RegisteredUserTableAdapter();
            adapter.Connection = AppSettings.GetDbConn();
            dsRegisteredUser.RegisteredUserDataTable tbl = adapter.GetData(registereduserid);

            if (tbl.Rows.Count == 1)
            {
                RegisteredUser registereduser = new RegisteredUser();
                RelationalToObject(registereduser, tbl.Rows[0]);
                return (registereduser);
            }
            else if (tbl.Rows.Count > 1)
                throw new ApplicationException("Database integrity error: Specified 'RegisteredUser' returned more than one User record.");

            return (null);
        }

        #endregion

        #region GetUserByUserName

        /// <summary>
        /// Returns an Registered User object for the specified 'username' or null if no User with the specified parameter(s) exists.
        /// </summary>
        public static RegisteredUser GetUserByUserName(string username)
        {
            RegisteredUserTableAdapter adapter = new RegisteredUserTableAdapter();
            adapter.Connection = AppSettings.GetDbConn();
            dsRegisteredUser.RegisteredUserDataTable tbl = adapter.GetDataByUserName(username);

            if (tbl.Rows.Count == 1)
            {
                RegisteredUser user = new RegisteredUser();
                RelationalToObject(user, tbl.Rows[0]);
                return (user);
            }
            else if (tbl.Rows.Count > 1)
                throw new ApplicationException("Database integrity error: Specified 'userLogin' returned more than one User record.");

            return (null);
        }

        #endregion

        #region GetUserByEmailAddress

        /// <summary>
        /// Returns an Registered User object for the specified 'EmailAddress' or null if no User with the specified parameter(s) exists.
        /// </summary>
        public static RegisteredUser GetUserByEmailAddress(string emailaddress)
        {
            RegisteredUserTableAdapter adapter = new RegisteredUserTableAdapter();
            adapter.Connection = AppSettings.GetDbConn();
            dsRegisteredUser.RegisteredUserDataTable tbl = adapter.GetDataByEmailAddress(emailaddress);

            if (tbl.Rows.Count == 1)
            {
                RegisteredUser user = new RegisteredUser();
                RelationalToObject(user, tbl.Rows[0]);
                return (user);
            }
            else if (tbl.Rows.Count > 1)
                throw new ApplicationException("Database integrity error: Specified 'EmailAddress' returned more than one User record.");

            return (null);
        }

        #endregion

        #region GetUserByUserGUID

        /// <summary>
        /// Returns an Registered User object for the specified 'username' or null if no User with the specified parameter(s) exists.
        /// </summary>
        public static RegisteredUser GetUserByUserGUID(Guid userGUID)
        {
            RegisteredUserTableAdapter adapter = new RegisteredUserTableAdapter();
            adapter.Connection = AppSettings.GetDbConn();
            dsRegisteredUser.RegisteredUserDataTable tbl = adapter.GetDataByUserGUID(userGUID);

            if (tbl.Rows.Count == 1)
            {
                RegisteredUser user = new RegisteredUser();
                RelationalToObject(user, tbl.Rows[0]);
                return (user);
            }
            else if (tbl.Rows.Count > 1)
                throw new ApplicationException("Database integrity error: Specified 'UserGUID' returned more than one User record.");

            return (null);
        }

        #endregion

        #region LogonUser

         /// <summary>
         /// General logon user method. Upon successful logon, the caller of this method is expected to handle the redirect.
         ///ASSUMPTION: The 'userLogin' MUST be an email address.
         /// </summary>
        public static RbsError LogonUser(string username, string clearTextPassword, out string errMsg)
        {
            errMsg = "";

             //Get the user from the database.
            RegisteredUser user = RegisteredUser.GetUserByUserName(username);
            if (username == "")
            { 
                //Required User Name.
                errMsg = "Plase enter a valid user name.";
                return(RbsError.INVALID_CREDENTIALS);
            }

            if (clearTextPassword == "")
            {
                //Required User Password.
                errMsg = "Plase enter Password.";
                return (RbsError.INVALID_CREDENTIALS);
            }


            if (user == null)
            {
                 //The UserLogin was not found.
                errMsg = "Your login details are not matched with our records, please try again or click on the registration link to register with us.";
                return (RbsError.NO_RECORDS_FOUND);
            }

            // Check the User's account status to determine whether they are still active, not locked-out, etc.
            if (!user.IsActive)
            {
                errMsg = "This user account is not active.";
                return (RbsError.ACCOUNT_INACTIVE);
            }

            // Check the User's account status to determine whether its email is verified or not.
            if (!user.IsRegistered)
            {
                errMsg = "The email address of this account is yet not verified.";
                return (RbsError.USER_EMAIL_NOT_VERIFIED);
            }

            
            if (clearTextPassword != null)
            {
                string hashedPswd = HashPassword(clearTextPassword);

                 //...for comparison to the DB-resident value.
                if (hashedPswd == user.Password)
                {
                    // Set the AppUser singleton to the logged-on user.
                    if (!RegisteredUser.SetCurrentAppUser(user, out errMsg))
                        return (RbsError.OTHER_EXCEPTION);


                    RegisteredUser.IncrementLoginCount(RegisteredUser.Current);

                         //Tell ASP.NET that this user is authenticated.
                         //Note: The caller of this method is expected to handle the redirect.
                        if (SessionMgr.IsWebApp)
                            System.Web.Security.FormsAuthentication.SetAuthCookie(username, false);

                        //user.SetIsAuthenticated(true);

                        errMsg = "";
                        return (RbsError.NO_ERROR);
                 
                }
                else
                {
                    errMsg = "Invalid credentials.";
                    return (RbsError.INVALID_CREDENTIALS);
                }
            }
            else  // An external DB authorized this user.
            {
                //Set the RegisteredUser singleton to the logged-on user.
                if (!RegisteredUser.SetCurrentAppUser(user, out errMsg))
                    return (RbsError.OTHER_EXCEPTION);

                RegisteredUser.IncrementLoginCount(RegisteredUser.Current);

                 //Tell ASP.NET that this user is authenticated.
                 //Note: The caller of this method is expected to handle the redirect.
                System.Web.Security.FormsAuthentication.SetAuthCookie(username, false);

                errMsg = "";
                return (RbsError.NO_ERROR);
            }
        }

        #endregion

        #region ValidatePassword

        /// <summary>
         //Validates the specified password against the app's password strength rules.
        /// </summary>
        public static RbsError ValidatePassword(string newPswd, out string errMsg)
        {
            errMsg = "";

            if (newPswd == null)
            {
                errMsg = "A password is required.";
                return (RbsError.PASSWORD_TOO_SHORT);
            }
            else if (newPswd.Length < REGISTEREDUSER_DFLT_MINPSWDLEN)
            {
                errMsg = "Password does not meet the minimum length requirements.";
                return (RbsError.PASSWORD_TOO_SHORT);
            }

            return (RbsError.NO_ERROR);
        }

        /// <summary>
        ///Determines whether or not the password is "strong" as defined by the RBS subsystem.
        /// </summary>
        ///<param name="password">The password to be tested.</param>
        ///<returns>True if the password is "strong"; false otherwise.</returns>
        public static bool IsStrongPassword(string password)
        {
            if (HasPunctuation(password) && HasNumbers(password))
                return (true);
            else return (false);
        }


        /// <summary>
        /// Determines whether or not the string contains punctuation.
        /// </summary>
        /// <returns>True if the string contains one or more punctuation characters.</returns>
        private static bool HasPunctuation(string str)
        {
             //Regex includes '_' as a valid char for alphanumeric, so we
             //need to explicity state that it's considered punctuation.
            Regex rgxTmp = new Regex(@"[\W|_]");
            return (rgxTmp.IsMatch(str));
        }


        /// <summary>
        ///Determines whether or not the string contains numbers.
        /// </summary>
        /// <returns>True if the string contains one or more numbers.</returns>
        private static bool HasNumbers(string str)
        {
            Regex rgxTmp = new Regex(@"[\d]");
            return (rgxTmp.IsMatch(str));
        }


         /// <summary>
         ///Determines whether or not the string contains lower-case characters.
         /// </summary>
         ///<returns>True if the string contains one or more lower-case characters.</returns>
        private static bool HasLowerCaseChars(string str)
        {
            Regex rgxTmp = new Regex("[a-z]");
            return (rgxTmp.IsMatch(str));
        }


        /// <summary>
        ///Determines whether or not the string contains upper-case characters.
        /// </summary>
        ///<returns>True if the string contains one or more upper-case characters.</returns>
        private static bool HasUpperCaseChars(string str)
        {
            Regex rgxTmp = new Regex("[A-Z]");
            return (rgxTmp.IsMatch(str));
        }

        #endregion

        #region HashPassword

        /// <summary>
        /// Returns the hashed version of the clear-text password.
        /// </summary>
        public static string HashPassword(string clearTextPswd)
        {
            return (HashPassword(clearTextPswd, REGISTEREDUSER_DFLT_PSWDSALT));
        }

        /// <summary>
        /// Returns the hashed version of the clear-text password.
        /// </summary>
        public static string HashPassword(string clearTextPswd, string salt)
        {
            // Append the salt value.
            string pswd = clearTextPswd + ((salt != null) ? salt : "");

            // Double-hash the password.
            pswd = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(pswd, "sha1");
            pswd = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(pswd, "sha1");

            return (pswd);
        }

        #endregion

        #region CreateRandomPassword

        public static string CreateRandomPassword(int passwordLength)
        {
            string allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789!@$?_-";
            char[] chars = new char[passwordLength];
            Random rd = new Random();

            for (int ndx = 0; ndx < passwordLength; ndx++)
            {
                chars[ndx] = allowedChars[rd.Next(0, allowedChars.Length)];
            }

            return new string(chars);
        }

        #endregion

        #region ValidatePasswordEntry / ValidateNewPasswordEntry

        /// <summary>
        /// Method validates the password/confirmPassword parameters.
        /// </summary>
        public static bool ValidatePasswordEntry(string password, string confirmPassword, out string passwordErrMsg, out string confirmPasswordErrMsg)
        {
            passwordErrMsg = "";
            confirmPasswordErrMsg = "";

            if ((password == null) || (password.Trim().Length == 0))
            {
                passwordErrMsg = "Password is required. Please try again.";
                return (false);
            }

            if ((confirmPassword == null) || (confirmPassword.Trim().Length == 0))
            {
                confirmPasswordErrMsg = "Confirm Password is required. Please try again.";
                return (false);
            }

            if (password.Trim().Length < REGISTEREDUSER_DFLT_MINPSWDLEN)
            {
                passwordErrMsg = String.Format("Password must be at least {0} characters in length. Please try again.", REGISTEREDUSER_DFLT_MINPSWDLEN);
                return (false);
            }

            //if (password.Trim().Length > SubAdmin.PasswordMaxLength)
            //{
            //    passwordErrMsg = String.Format("Password must be less than {0} characters in length. Please try again.", SubAdmin.PasswordMaxLength);
            //    return (false);
            //}

            if (confirmPassword.Trim().Length < REGISTEREDUSER_DFLT_MINPSWDLEN)
            {
                confirmPasswordErrMsg = String.Format("Confirm Password must be at least {0} characters in length. Please try again.", REGISTEREDUSER_DFLT_MINPSWDLEN);
                return (false);
            }

            //if (confirmPassword.Trim().Length > SubAdmin.PasswordMaxLength)
            //{
            //    confirmPasswordErrMsg = String.Format("Confirm Password must be less than {0} characters in length. Please try again.", SubAdmin.PasswordMaxLength);
            //    return (false);
            //}

            if (password.Trim() != confirmPassword.Trim())
            {
                passwordErrMsg = "Passwords do not match. Please try again.";
                confirmPasswordErrMsg = "Passwords do not match. Please try again.";
                return (false);
            }

            return (true);
        }


        /// <summary>
        /// Method validates the oldPassword/newPassword/confirmPassword parameters.
        /// </summary>
        public static bool ValidateNewPasswordEntry(string oldPassword, string newPassword, string confirmPassword, out string newPasswordHash, out string passwordErrMsg, out string confirmPasswordErrMsg)
        {
            newPasswordHash = null;

            if (!ValidatePasswordEntry(newPassword, confirmPassword, out passwordErrMsg, out confirmPasswordErrMsg))
                return (false);

            if (oldPassword == SubAdmin.HashPassword(newPassword.Trim()))
            {
                passwordErrMsg = "Password must be different than current password. Please try again.";
                confirmPasswordErrMsg = "";
                return (false);
            }

            newPasswordHash = SubAdmin.HashPassword(newPassword.Trim());

            return (true);
        }

        #endregion

        #region Update

        /// <summary>
        /// Updates the specified RegisteredUser.
        /// </summary>
        public static void Update(RegisteredUser obj)
        {
            bool updateRegisteredUser = false;

            // Do not update invalid objects.
            if (!obj.Validate())
            {
                StringBuilder sb = new StringBuilder(2048);
                sb.Append("The object being updated has one or more invalid properties; the Update() operation for this object has been cancelled.\nError(s):");
                foreach (ValidationError err in obj.Errors)
                    sb.Append("\n* " + err.Element + ": " + err.Message);

                throw new InvalidObjectException(sb.ToString());
            }
            else
            {
                updateRegisteredUser = (obj.ObjState != ObjectState.Unchanged);

                if (!updateRegisteredUser)
                    return;
            }

            ObjectState originalObjectState = obj.ObjState;

            dsRegisteredUser.RegisteredUserDataTable tbl = null;
            if (updateRegisteredUser)
            {
                RegisteredUserTableAdapter adapter = new RegisteredUserTableAdapter();
                adapter.Connection = AppSettings.GetDbConn();

                tbl = new dsRegisteredUser.RegisteredUserDataTable();
                dsRegisteredUser.RegisteredUserRow row = tbl.NewRegisteredUserRow();
                ObjectToRelational(obj, tbl, row);

                adapter.Update(tbl);

                if (originalObjectState == ObjectState.Deleted)
                    obj = null;
                else RelationalToObject(obj, tbl.Rows[0]);
            }
        }

        #endregion

        #region Validate

        /// <summary>
        /// Validates the object based on its properties at the time of the call; updates the Errors property.
        /// </summary>
        public override bool Validate()
        {
            Errors.Clear();

            if (ObjState == ObjectState.Unchanged)
            {
                // By definition, unchanged objects are valid.
                return (true);
            }
            else if (ObjState == ObjectState.Uninitialized)
            {
                Errors.Add(new ValidationError("object", "Object is uninitialized.", ValidationError.Severity.Error));

                // No need to proceed past this error.
                return (false);
            }
            else if ((ObjState == ObjectState.Deleted) && (RegisteredUserID <= 0))
            {
                // Deleted items must have 'real' (i.e. non-negative, non-zero) key(s) to be valid.
                Errors.Add(new ValidationError("RegisteredUserID", "Deleted object has an invalid PKID.", ValidationError.Severity.Error));

                // No need to proceed past this error.
                return (false);
            }
            else  // ObjState == Added | Modified
            {

                // UserName is required.
                //if ((Question == null) || (Question.Trim().Length == 0))
                //{
                //    Errors.Add(new ValidationError("Question", "Question is required.", ValidationError.Severity.Error));
                //}
                //else if (ObjState == ObjectState.Added)
                //{

                //}

            }

            return (Errors.Count == 0);
        }

        #endregion

        #region ToString

        /// <summary>
        /// User-friendly string represetation of this object.
        /// </summary>
        public override string ToString()
        {
            return (String.Format("RegisteredUser: RegisteredUserID={0}, UserName={1}, {2}", RegisteredUserID, UserName));
        }

        #endregion

        #endregion

        #region Privates

        #region SetCurrentAppUser

        /// <summary>
        /// Sets the Current property to the specified RegisteredUser object.
        /// </summary>
        private static bool SetCurrentAppUser(RegisteredUser user, out string errMsg)
        {
            errMsg = "";

            lock (typeof(RegisteredUser))
            {
                SessionMgr.Session[PROP_CURRENT] = user;
            }

            // Load the appropriate navigation/menu items for AppUser.Current.
            //Navigation.ClearCachedNavData();

            return (true);
        }

        #endregion

        #region IncrementLoginCount

        /// <summary>
        /// Method increments the LoginCount property of the specified 'user' and invokes a
        /// stored-procedure to store the new count without changing the LastModifiedByID and
        /// LastModifiedDate fields of the corresponding User row in the database.
        /// </summary>
        private static void IncrementLoginCount(RegisteredUser user)
        {
            user.LoginCount++;

            RegisteredUserTableAdapter adapter = new RegisteredUserTableAdapter();
            adapter.Connection = AppSettings.GetDbConn();
            dsRegisteredUser.RegisteredUserDataTable tbl = new dsRegisteredUser.RegisteredUserDataTable();

            dsRegisteredUser.RegisteredUserRow row = tbl.NewRegisteredUserRow();
            ObjectToRelational(user, tbl, row);

            adapter.UpdateLoginCount(tbl, user.RegisteredUserID, user.LoginCount);

            RelationalToObject(user, tbl.Rows[0]);
        }

        #endregion

        #endregion

    }

    /// <summary>
    /// Collection of 0 or more RegisteredUser objects.
    /// </summary>

    public class RegisteredUserCollection : List<RegisteredUser>
    {
        #region Types

        public class UserComparer : IComparer<RegisteredUser>
        {
            public int Compare(RegisteredUser ru1, RegisteredUser ru2)
            {
                return (String.Compare(ru1.UserName, ru2.UserName));
            }
        }

        #endregion

        #region Public Methods

        #region FindByRegisteredUserID

        public RegisteredUser FindByRegisteredUserID(int registereduserID)
        {
            for (int ndx = 0; ndx < this.Count; ndx++)
                if (this[ndx].RegisteredUserID == registereduserID)
                    return (this[ndx]);

            return (null);
        }

        #endregion

        #region FindRegisteredUserByUserName

        /// <summary>
        /// Case insensitve compare.
        /// </summary>
        public RegisteredUser FindRegisteredUserByUserName(string username)
        {
            for (int ndx = 0; ndx < this.Count; ndx++)
                if (this[ndx].UserName == username)
                    return (this[ndx]);

            return (null);
        }

        #endregion

        #endregion
    }
}
